﻿using DiLe.Mes.Model.Common.Organization.Entity;
using MapleLeaf.Core.Serilog;
using MapleLeaf.DataBase.Const;
using MapleLeaf.DataBase.Entity;
using Yitter.IdGenerator;

namespace DiLe.Mes.Local.Components {
    /// <summary>
    /// 
    /// </summary>
    public static class SqlSugarComponent {

        private static readonly string DbStr = AppHelper.GetConfig("ConnectionStrings", "ConnectionString");
        private static readonly SnowIdOptions snowIdOptions = AppHelper.GetConfig<SnowIdOptions>("SnowIdOptions");
        /// <summary>
        /// 
        /// </summary>
        /// <param name="builder"></param>
        public static void AddSqlSugarSetup(this WebApplicationBuilder builder) {
            List<ConnectionConfig> dbConfigs = [
                new ConnectionConfig { ConfigId = DataBaseConfigIdConst.Public, DbType = DbType.PostgreSQL, ConnectionString = $"{DbStr};searchpath=public" },
                new ConnectionConfig { ConfigId = DataBaseConfigIdConst.Local, DbType = DbType.PostgreSQL, ConnectionString = $"{DbStr};searchpath=local" }
            ];

            // 注册雪花Id
            YitIdHelper.SetIdGenerator(snowIdOptions);

            // 自定义 SqlSugar 雪花ID算法
            SnowFlakeSingle.WorkId = snowIdOptions.WorkerId;
            StaticConfig.CustomSnowFlakeFunc = YitIdHelper.NextId;

            dbConfigs.ForEach(SetDbConfig);

            //注册SqlSugar
            builder.Services.AddSingleton<ISqlSugarClient>(s => {
                //单例不要写在泛型类中， 类<T>.Db 这种是无效单例 ，T不同就会有多个实例
                SqlSugarScope Db = new(dbConfigs,
                 db => {
                     dbConfigs.ForEach(config => {
                         var dbProvider = db.GetConnectionScope(config.ConfigId);
                         SetDbAop(dbProvider);
                         //SetDbDiffLog(dbProvider, config);
                     });
                 });
                return Db;
            });

        }

        /// <summary>
        /// 配置连接属性
        /// </summary>
        /// <param name="config"></param>
        public static void SetDbConfig(ConnectionConfig config) {
            var configureExternalServices = new ConfigureExternalServices {
                // 处理表
                EntityNameService = (type, entity) => {
                    // 禁止删除非 sqlsugar 创建的列
                    entity.IsDisabledDelete = true;
                    // 只处理贴了特性[SugarTable]表
                    if (!type.GetCustomAttributes<SugarTable>().Any())
                        return;
                },
                // 处理列
                EntityService = (type, column) => {
                    // 只处理贴了特性[SugarColumn]列
                    //if (!type.GetCustomAttributes<SugarColumn>().Any())
                    //    return;
                    // 支持string? 和string
                    if (column.IsPrimarykey == false && new NullabilityInfoContext().Create(type).WriteState is NullabilityState.Nullable) {
                        column.IsNullable = true;
                    }
                }
            };
            config.ConfigureExternalServices = configureExternalServices;
            config.InitKeyType = InitKeyType.Attribute;
            config.IsAutoCloseConnection = true;
            config.MoreSettings = new ConnMoreSettings {
                IsAutoRemoveDataCache = true,
                IsAutoDeleteQueryFilter = true, // 启用删除查询过滤器
                IsAutoUpdateQueryFilter = true, // 启用更新查询过滤器
                SqlServerCodeFirstNvarchar = true // 采用Nvarchar
            };
        }


        /// <summary>
        /// Aop设置
        /// </summary>
        /// <param name="db"></param>
        public static void SetDbAop(SqlSugarScopeProvider db) {
            var config = db.CurrentConnectionConfig;

            // 设置超时时间
            db.Ado.CommandTimeOut = 30;

            //异常
            db.Aop.OnError = (ex) => {
                if (ex.Parametres == null)
                    return;
                var pars = db.Utilities.SerializeObject(((SugarParameter[])ex.Parametres).ToDictionary(it => it.ParameterName, it => it.Value));
                var exsql = UtilMethods.GetSqlString(config.DbType, ex.Sql, (SugarParameter[])ex.Parametres);
                //如果是开发环境就打印日志
                if (AppHelper.HostEnvironment!.IsDevelopment()) {
                    Console.WriteLine($"{config.ConfigId}库操作异常,执行SQL:{exsql}");
                } else {
                    WriteSqlErrorLog($"{config.ConfigId}库操作异常,执行SQL:{exsql}");
                }
            };
            //插入和更新过滤器
            db.Aop.DataExecuting = (oldValue, entityInfo) => {
                var userinfo = AppHelper.LoginUserInfo;
                // 新增操作
                if (entityInfo.OperationType == DataFilterType.InsertByObject) {
                    // 主键(long类型)且没有值的---赋值雪花Id
                    if (entityInfo.EntityColumnInfo.IsPrimarykey && entityInfo.EntityColumnInfo.PropertyInfo.PropertyType == typeof(long)) {
                        var id = entityInfo.EntityColumnInfo.PropertyInfo.GetValue(entityInfo.EntityValue);
                        if (id == null || (long)id == 0)
                            entityInfo.SetValue(YitIdHelper.NextId());
                    }
                    if (entityInfo.PropertyName == nameof(AbstractBaseEntity.CreateTime))
                        entityInfo.SetValue(DateTime.Now);

                    if (userinfo != null) {
                        //创建人和创建机构ID
                        if (entityInfo.PropertyName == nameof(DataEntityBase.CreateUserId))
                            entityInfo.SetValue(userinfo.Id);
                        if (entityInfo.PropertyName == nameof(DataEntityBase.CreateUser))
                            entityInfo.SetValue(userinfo.Name);
                        if (entityInfo.PropertyName == nameof(DataEntityBase.FactoryId))
                            entityInfo.SetValue(userinfo.OrgId);
                        //更新时间
                        if (entityInfo.PropertyName == nameof(DataEntityBase.UpdateTime)) {
                            entityInfo.SetValue(DateTime.Now);
                        }
                        //更新人
                        if (entityInfo.PropertyName == nameof(DataEntityBase.UpdateUserId))
                            entityInfo.SetValue(userinfo.Id);
                        if (entityInfo.PropertyName == nameof(DataEntityBase.UpdateUser))
                            entityInfo.SetValue(userinfo.Name);
                    }
                }
                // 更新操作
                if (entityInfo.OperationType == DataFilterType.UpdateByObject) {
                    //更新时间
                    if (entityInfo.PropertyName == nameof(DataEntityBase.UpdateTime))
                        entityInfo.SetValue(DateTime.Now);
                    //更新人
                    if (userinfo != null) {
                        if (entityInfo.PropertyName == nameof(DataEntityBase.UpdateUserId))
                            entityInfo.SetValue(userinfo?.Id);
                        if (entityInfo.PropertyName == nameof(DataEntityBase.UpdateUser))
                            entityInfo.SetValue(userinfo?.Name);
                    }
                }
            };
            //查询数据转换
            db.Aop.DataExecuted = (value, entity) => {

            };
            db.Aop.OnLogExecuting = (sql, pars) => {
                Console.WriteLine(sql);//输出sql,查看执行sql 性能无影响
            };
        }
        ///// <summary>
        ///// 开启库表差异化日志
        ///// </summary>
        ///// <param name="db"></param>
        ///// <param name="config"></param>
        //private static void SetDbDiffLog(SqlSugarScopeProvider db, ConnectionConfig config) {
        //    db.Aop.OnDiffLogEvent = async u => {
        //        var logDiff = new SysLogDiffEntity {
        //            // 操作后记录（字段描述、列名、值、表名、表描述）
        //            AfterData = JsonConvert.SerializeObject(u.AfterData),
        //            // 操作前记录（字段描述、列名、值、表名、表描述）
        //            BeforeData = JsonConvert.SerializeObject(u.BeforeData),
        //            // 传进来的对象
        //            BusinessData = JsonConvert.SerializeObject(u.BusinessData),
        //            // 枚举（insert、update、delete）
        //            DiffType = u.DiffType.ToString(),
        //            Sql = UtilMethods.GetSqlString(config.DbType, u.Sql, u.Parameters),
        //            Parameters = JsonConvert.SerializeObject(u.Parameters),
        //            Elapsed = u.Time == null ? 0 : (long)u.Time.Value.TotalMilliseconds
        //        };
        //        await db.Insertable(logDiff).ExecuteCommandAsync();
        //    };
        //}
        /// <summary>
        /// 
        /// </summary>
        /// <param name="msg"></param>
        private static void WriteSqlLog(string msg) {
            SerilogLogHelper.WriteSqlLog(msg);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="msg"></param>
        private static void WriteSqlErrorLog(string msg) {
            SerilogLogHelper.WriteSqlErrorLog(msg);
        }

    }
}
